import WebGl from '@/modules/three';
// import fontJson from 'three/examples/fonts/helvetiker_regular.typeface.json'
// const fontJson = require('three/examples/fonts/helvetiker_regular.typeface.json');

const {
  Three,
  TWEEN,
  OrbitControls,
  dat,
  Stats,
  OBJLoader,
  MTLLoader,
  GLTFLoader,
  CalcThree,
} = WebGl;

class WebGlControl {
  private container: any;
  private camera: any;
  private camera2: any;
  private scene: any;
  private renderer: any;
  private stats: any;
  private animateFrame: any;
  private tween: any;
  private mixer: any; //glb的animation
  private clock: any = new Three.Clock();
  private controls: any;

  private Geometrys: {} = {}; //保存所有Geometry，方便统一销毁
  private Materials: {} = {}; //保存所有Material，方便统一销毁
  private Meshs: {
    bird?: any;
    sphereMesh?: any;
    sphereRandom?: any;
  } = {};
  private birdGroup: any = {};
  private ballsGroup: any = {};

  private GuiInit: any = null;
  private guiData: any = {
    x: 0.005,
    color: '#000000',
    autoRotate: true,
    selfControl: false,
    showHelpBall: false,
  };
  private birdAnimate: any = {
    direction: new Three.Vector3(1, 0, 0),
    // directionTrend: new Three.Vector3(0, 0, 1), // 方向变换的方向，应该是垂直于direction的向量
    // maxAngle: 0.1, // // 最大变换角度（以弧度表示）
    speed: 15,
    speedDecay: 0, //速度衰减，-1,1
  };
  private moveState = {
    up: 0,
    down: 0,
    left: 0,
    right: 0,
    rollLeft: 0,
    rollRight: 0,
  }; //旋转控制
  private rotateQuaternion = new Three.Quaternion(); //当前旋转
  private birdUp = new Three.Vector3(0, 1, 0); //上
  private rotateSpeed = new Three.Vector3(1, 1, 1); //每个轴的旋转速度
  private targetPosition = new Three.Vector3(0, 0, 0); //目标点位
  private mouseData: any = {
    mouseX: 0,
    mouseY: 0,
  };
  private pointer = new Three.Vector2(-2, -2); //初始化在[-1,1]以外

  public init = (id: string) => {
    // if(this.scene) {return}
    this.container = document.getElementById(id);
    let width = this.container.clientWidth,
      height = this.container.clientHeight;

    this.scene = new Three.Scene();
    this.scene = new Three.Scene();

    this.camera = new Three.PerspectiveCamera(45, width / height, 1, 500);
    this.camera.position.x = 0;
    this.camera.position.y = 0;
    this.camera.position.z = 150;
    this.camera.lookAt(this.scene.position);

    // this.camera2 = new Three.PerspectiveCamera(45, width / height, 1, 500);
    // this.camera2.position.z = -140;
    // this.camera.add(this.camera2)

    this.renderer = new Three.WebGLRenderer();
    // this.renderer.setClearColor( 0xffffff );
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(width, height);
    this.renderer.autoClear = false;
    this.container.appendChild(this.renderer.domElement);

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.controls.enableDamping = true; //阻尼
    this.controls.dampingFactor = 0.1; //阻尼

    this.addThings();
    this.addLight(); //+光源
    this.animate(); //开始动
    this.initStats();
    this.initEventListen();

    this.initGui();
  };
  public destroy = () => {
    this.toggleGui(0);
    Object.values(this.Geometrys).forEach((e) => {
      e.dispose();
    });
    Object.values(this.Materials).forEach((e) => {
      e.dispose();
    });
    this.scene.clear();
    this.renderer.dispose();
    this.renderer.forceContextLoss();
    this.camera = null;
    this.camera2 = null;
    this.scene = null;
    this.renderer = null;
    this.GuiInit = null;
    this.stats = null;
    if (this.tween) {
      this.tween.stop();
      this.tween = null;
    }
    this.birdGroup = null;
    this.ballsGroup = null;
    cancelAnimationFrame(this.animateFrame);
  };

  private initEventListen = () => {
    this.container.addEventListener('pointermove', this.onPointerMove);
    document.addEventListener('keydown', this.onKeyDown);
    document.addEventListener('keyup', this.onKeyUp);
  };
  private onPointerMove = (event) => {
    if (event.isPrimary === false) return;
    // this.mouseData.mouseX = event.clientX - this.container.clientWidth;
    // this.mouseData.mouseY = event.clientY - this.container.clientHeight;
    this.mouseData.mouseX = event.clientX - this.container.offsetLeft;
    this.mouseData.mouseY = event.clientY - this.container.offsetTop;
    var scrollTop = window.pageYOffset || document.documentElement.scrollTop; //在container中的位置要考虑scroll

    // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
    this.pointer.x =
      (this.mouseData.mouseX / this.container.clientWidth) * 2 - 1;
    this.pointer.y =
      -((this.mouseData.mouseY + scrollTop) / this.container.clientHeight) * 2 +
      1;
    // console.log('this.pointer', event.clientY, this.container.offsetTop, )
  };
  private onKeyDown = (event) => {
    if (event.keyCode === 38) {
      // 上键
      this.moveState.up = 1;
      event.preventDefault && event.preventDefault();
      event.returnValue = false;
      event.stopPropagation && event.stopPropagation();
      return false;
    } else if (event.keyCode === 40) {
      // 下键
      this.moveState.down = 1;
      event.preventDefault && event.preventDefault();
      event.returnValue = false;
      event.stopPropagation && event.stopPropagation();
      return false;
    } else if (event.keyCode === 37) {
      // 左键
      this.moveState.left = 1;
    } else if (event.keyCode === 39) {
      // 右键
      this.moveState.right = 1;
    } else if (event.code == 'KeyQ') {
      this.moveState.rollLeft = 1;
    } else if (event.code == 'KeyE') {
      this.moveState.rollRight = 1;
    }
  };
  private onKeyUp = (event) => {
    if (event.keyCode === 38) {
      // 上键
      this.moveState.up = 0;
    } else if (event.keyCode === 40) {
      // 下键
      this.moveState.down = 0;
    } else if (event.keyCode === 37) {
      // 左键
      this.moveState.left = 0;
    } else if (event.keyCode === 39) {
      // 右键
      this.moveState.right = 0;
    } else if (event.code == 'KeyQ') {
      this.moveState.rollLeft = 0;
    } else if (event.code == 'KeyE') {
      this.moveState.rollRight = 0;
    }
  };

  private initStats = () => {
    this.stats = new Stats();
    this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
    this.stats.dom.style.position = 'absolute';
    this.container.appendChild(this.stats.dom);
  };

  public initGui = () => {
    if (this.GuiInit) {
      this.toggleGui();
      return;
    }
    this.GuiInit = new dat.GUI({
      // autoPlace: false
    });

    this.GuiInit.domElement.style.position = 'absolute';
    this.GuiInit.domElement.style.right = '10px';
    this.GuiInit.domElement.style.top = '10px';

    let guiCt = this.GuiInit.addFolder('控制窗口');
    guiCt.addColor(this.guiData, 'color').name('背景颜色');
    guiCt.open();
    let guiCt1 = this.GuiInit.addFolder('小鸟');
    guiCt1.add(this.birdAnimate, 'speed', 10, 25, 0.1).name('速度');
    guiCt1.add(this.guiData, 'selfControl').name('键盘控制');
    guiCt1.add(this.guiData, 'showHelpBall').name('辅助球');
    guiCt1.open();

    // let cubeGui = this.GuiInit.addFolder("cube position");
    // cubeGui.open()
  };

  public toggleGui = (state: any = null) => {
    if (!this.GuiInit || !this.GuiInit.domElement) {
      return;
    }
    let display = this.GuiInit.domElement.style.display == 'none' ? '' : 'none';
    if (state == 0) {
      display = 'none';
    }
    this.GuiInit.domElement.style.display = display;
  };

  private addLight = () => {
    let ambi = new Three.AmbientLight(0x686868);
    this.scene.add(ambi);
    let dirlight = new Three.DirectionalLight(0xffffff);
    dirlight.position.set(550, 100, 550);
    dirlight.intensity = 0.6;
    this.scene.add(dirlight);
    // let light = new Three.PointLight( 0xFFFF00 );
    // light.position.set( -100, 100, 0 );
    // this.scene.add(light);
  };

  private addThings = () => {
    // const axesHelper = new Three.AxesHelper( 800 );
    // this.scene.add( axesHelper )  //添加坐标轴；红线是X轴，绿线是Y轴，蓝线是Z轴

    this.birdGroup = new Three.Group();
    this.scene.add(this.birdGroup);
    this.ballsGroup = new Three.Group();
    this.scene.add(this.ballsGroup);
    this.addBird();
    this.addball();

    // console.log('this.birdAnimate,', this.birdAnimate.direction)
    // this.birdAnimate.direction.multiplyScalar(0.14)
    // this.birdAnimate.direction.normalize()
    // console.log('this.birdAnimate1,', this.birdAnimate.direction)

    this.initTween();
  };

  private addball = () => {
    const geometry = new Three.SphereGeometry(1, 26, 15);
    const material = new Three.MeshBasicMaterial({ color: 0xfdffff });
    this.Meshs.sphereMesh = new Three.Mesh(geometry, material);
    this.ballsGroup.add(this.Meshs.sphereMesh); //鸟朝向

    const material1 = new Three.MeshBasicMaterial({ color: 0xff0ea0 });
    const origin = new Three.Mesh(geometry, material1);
    this.ballsGroup.add(origin); //原点

    this.Meshs.sphereRandom = new Three.Mesh(geometry, material1);
    this.ballsGroup.add(this.Meshs.sphereRandom);
  };

  private addBird = () => {
    new GLTFLoader().load('../models/Parrot.glb', (gltf) => {
      // console.log('glbbbbb:', gltf, gltf.animations);
      // gltf.animations;
      this.mixer = new Three.AnimationMixer(gltf.scene);
      gltf.animations.forEach((animations) => {
        this.mixer.clipAction(animations).play();
      });

      this.Meshs.bird = gltf.scene.children[0];
      // this.Meshs.bird.rotation.order = 'XZY';
      // console.log('this.Meshs.bird', this.Meshs.bird)
      // const birdGeo = this.Meshs.bird.geometry;
      this.Meshs.bird.scale.set(0.2, 0.2, 0.2);
      this.birdGroup.add(gltf.scene);
      console.log('bird', this.Meshs.bird);
    });

    // const a = new Three.Vector3(0,0,1);
    // const b = new Three.Vector3(1,0,0);
    // console.log('a+b:', a.add(b).multiplyScalar(-1))
  };

  private initTween = () => {
    // var pos: any = { val: 1 };
    // this.tween = new TWEEN.Tween(pos)
    //   .to({ val: 0 }, 1000)
    //   .easing(TWEEN.Easing.Quadratic.InOut)
    //   .delay(200)
    //   .onUpdate(callback);
    // let tweenBack = new TWEEN.Tween(pos)
    //   .to({ val: 1 }, 1000)
    //   .easing(TWEEN.Easing.Quadratic.InOut)
    //   .delay(200)
    //   .onUpdate(callback);
    // this.tween.chain(tweenBack);
    // tweenBack.chain(this.tween);
    // this.tween.start();
    // let that = this;
    // function callback(res) {
    //   that.Materials.starsMaterial.uniforms.val.value = res.val;
    // }
  };

  private calcMove = (delta: number) => {
    // return;
    const { speed, direction } = this.birdAnimate;
    const dir = new Three.Vector3();
    dir.copy(direction);
    dir.normalize(); //归一
    // 计算每一帧物体在每个轴上的位移量
    dir.multiplyScalar(delta * speed);
    // 计算新位置

    if (this.birdGroup) {
      //计算路径切线，调整朝向
      // const target = direction.clone().add(this.birdGroup.position)
      // this.birdGroup.lookAt(target)  //不能直接这样控制朝向，上下翻转很生硬
      this.birdGroup.position.add(dir);
      // console.log('this.birdGroup', dir)
    }
  };

  // private calcDirection = (delta: number) => {
  //   // return;
  //   const { direction, directionTrend, maxAngle } = this.birdAnimate;

  //   // 生成随机变换角度（范围在 -maxAngle 到 maxAngle 之间）

  //   const axis = CalcThree.vecProjectionDir(direction, directionTrend); // 计算directionTrend在direction方向的分量向量
  //   const newDirection = direction
  //     .clone()
  //     .applyAxisAngle(axis.normalize(), 0.005); //direction绕轴旋转角度
  //   // 标准化新的方向向量
  //   newDirection.normalize();

  //   // 将新的方向向量赋值给当前方向
  //   this.birdAnimate.direction = newDirection;
  // };

  private calcRotation = (delta: number) => {
    // 通过moveState和rotateSpeed控制旋转
    const { direction } = this.birdAnimate;

    // const matrix = new Three.Matrix4();
    // matrix.copy(this.Meshs.bird?.matrix);

    const axis = new Three.Vector3(0, 0, 0);
    axis.y = this.moveState.left - this.moveState.right;
    axis.x = this.moveState.down - this.moveState.up;
    axis.z = -this.moveState.rollLeft + this.moveState.rollRight;

    // const quaternion = new Three.Quaternion();

    // const rotMult = delta * 0.1;
    this.rotateQuaternion
      .set(
        axis.x * this.rotateSpeed.x * 0.01,
        axis.y * this.rotateSpeed.y * 0.01,
        axis.z * this.rotateSpeed.z * 0.01,
        1,
      )
      .normalize();
    // console.log('this.rotateQuaternion', this.rotateQuaternion)
    this.Meshs.bird?.quaternion.multiply(this.rotateQuaternion);

    //转向后，通过matrix获取当前朝向
    if (this.Meshs.bird) {
      const dir = new Three.Vector3(0, 0, -1);
      dir.applyMatrix4(this.Meshs.bird.matrix);
      // console.log(dir.addScalar(5));
      this.birdAnimate.direction = dir.multiplyScalar(-1).normalize(); //设置当前运动方向
      // this.birdAnimate.direction.lerp(dir.normalize(), 0.1)
    }
    //转向后，通过matrix获取当前朝向
  };

  private randomDurationMax: number = 3;
  private randomDuration: number = 0;
  private randomTarget = (delta: number) => {
    if (this.targetPosition.clone().sub(this.birdGroup.position).length() < 5) {
      this.randomDuration = this.randomDurationMax;
    }
    if (this.randomDuration < this.randomDurationMax) {
      this.randomDuration += delta;
    } else {
      this.randomDuration = 0;
      const x = Math.random() * 100 - 50;
      const y = Math.random() * 100 - 50;
      const z = Math.random() * 100 - 50;
      this.targetPosition.set(x, y, z);
      this.Meshs.sphereRandom?.position.copy(this.targetPosition);
    }
  };

  private _m1 = new Three.Matrix4();
  private FlyToTarget = (delta: number) => {
    if (this.Meshs.bird) {
      let dir = this.targetPosition
        .clone()
        .sub(this.birdGroup.position)
        .normalize(); // 计算方向向量
      // let difDir = dir.clone().sub(this.birdAnimate.direction).normalize();
      const target = this.birdAnimate.direction
        .clone()
        .lerp(dir, 0.1)
        .add(this.birdGroup.position.clone());
      this.birdAnimate.direction = this.birdAnimate.direction.lerp(dir, 0.02);

      this.caculateUp();
      //
      // this.Meshs.bird?.lookAt(target)
      this._m1.lookAt(target, this.birdGroup.position, this.birdUp);
      this.rotateQuaternion.setFromRotationMatrix(this._m1);
      this.Meshs.bird?.quaternion.copy(this.rotateQuaternion);
    }
  };

  private prevDirection = new Three.Vector3();
  private caculateUp = () => {
    const { direction } = this.birdAnimate;
    //动态调整this.birdUp
    const UP = new Three.Vector3(0, 1, 0);
    // this.birdUp.lerp()

    const angle = direction.angleTo(this.prevDirection);
    const shift = direction
      .clone()
      .add(this.prevDirection)
      .multiplyScalar(-1)
      .normalize(); //转角的反向，UP的趋势方向
    const up = UP.clone()
      .addScaledVector(shift, angle * 100)
      .normalize();
    this.birdUp.copy(up);

    // console.log('this.birdUp', this.birdUp)

    this.prevDirection.copy(direction); //
  };

  private animate = () => {
    // if(!this.renderer){return;}
    if (this.stats) {
      this.stats.begin();
    }

    this.render();
    TWEEN.update();
    this.controls.update();

    if (this.stats) {
      this.stats.end();
    }
    this.animateFrame = requestAnimationFrame(this.animate);
  };
  private render = () => {
    const delta = this.clock.getDelta();
    if (this.mixer) this.mixer.update(delta);

    // this.calcDirection(delta); //调整方向
    this.calcMove(delta);
    if (this.guiData.selfControl) {
      this.calcRotation(delta); //键盘控制方向
    } else {
      this.randomTarget(delta);
      this.FlyToTarget(delta);
    }

    if (this.Meshs.bird) {
      const dir = new Three.Vector3(0, 0, -1);
      dir.applyMatrix4(this.Meshs.bird.matrix);
      this.Meshs.sphereMesh?.position.copy(dir.multiplyScalar(-5)); //测试小球位置
    }
    this.ballsGroup.visible = this.guiData.showHelpBall;

    // this.updateBird()  //test
    this.renderer.clear();
    this.renderer.setClearColor(this.guiData.color, 1.0);

    let width = this.container.clientWidth,
      height = this.container.clientHeight;
    this.renderer.setViewport(0, 0, width, height);
    this.renderer.render(this.scene, this.camera);

    // this.renderer.setViewport(width - 100 - 10, height - 100 - 10 , 100, 100);
    // this.renderer.render(this.scene, this.camera2);
  };
}

const webGlControl = new WebGlControl();
export default webGlControl;
